#include "CubeApp.h"
#include "NeroGame\Nero.h"
#include "Win32\Win32.h"
#include "DirectX\DirectX11.h"

using namespace Game;

//CubeApp CubeApp::s_instance;

RTTI_DEFINITIONS(CubeApp)

CubeApp::CubeApp(void)
	:NGame(),
	mCube(NULL),
	mCurrentState(State::Refletion_State)
{
}

CubeApp::~CubeApp(void)
{
	Deinitialize();
}

void CubeApp::Initialize(const std::string& scene)
{
	NGame::Initialize(scene);

	mCube = MY_NEW(Memory::HID_Game, "Cube") Cube();
	mCube->Initialize();

	mFloor =  MY_NEW(Memory::HID_Game, "Floor") Floor();
	mFloor->Initialize("Floor");

	mTextureShader = MY_NEW(Memory::HID_Rendering, "Texture Shader") Graphics::TextureShader();
	mTextureShader->Initialize();
	
	mLightShader = MY_NEW(Memory::HID_Rendering, "Light Shader") Graphics::LightShader();
	mLightShader->Initialize();

	mLight = MY_NEW(Memory::HID_Rendering,"Light") Graphics::Light();
	mLight->Initialize();

	mReflectionShader = MY_NEW(Memory::HID_Rendering, "Reflection Shader") Graphics::ReflectionShader();
	mReflectionShader->Initialize();

	mRenderTarget = MY_NEW(Memory::HID_Rendering, "Render Target") Graphics::RenderTarget();
	mRenderTarget->Initialize(1280, 720, 100, 100);

	GetPlatform()->GetCamera()->SetPosition(NVector3(0.0f,0.0f,-10.0f));
	mIsInitialized = true;
}

void CubeApp::Deinitialize()
{
	if(mIsInitialized)
	{
		MY_DELETE(mCube);
		MY_DELETE(mLight);
		MY_DELETE(mLightShader);
		MY_DELETE(mTextureShader);
		MY_DELETE(mReflectionShader);
		NGame::Deinitialize();
		mIsInitialized = false;
	}
}

void CubeApp::Update(float gameTime)
{
	NGame::Update(gameTime);

    mFloor->Update(gameTime);
}

void CubeApp::Render()
{
	static float rotation = 0.0f;
	if(mIsInitialized)
	{
		D3DXMATRIX worldMatrix, viewMatrix, projectionMatrix;
		Graphics::D3DDevice* device = GetPlatform()->GetDevice()->As<Graphics::D3DDevice>();

		worldMatrix = device->GetWorldMatrix();
		projectionMatrix = device->GetProjectionMatrix();
		viewMatrix = Graphics::Utility::NeroToDXD(GetPlatform()->GetCamera()->GetViewMatrix());

		D3DXMATRIX reflectionViewMatrix;
		System::Win32Graphics* graphics = (System::Win32Graphics*)GetPlatform()->GetGraphics();
		Graphics::Camera* camera = GetPlatform()->GetCamera()->As<Graphics::Camera>();

		switch (mCurrentState)
		{
		case No_State:
			break;

		case Refletion_State:
				if(graphics)
				{
					mCube->Render();

					mTextureShader->Render(mCube->GetIndexCount(), 1, worldMatrix, viewMatrix, projectionMatrix, Graphics::TextureResourceManager::GetInstance()->GetResource("SeaFloor"));

					D3DXMatrixTranslation(&worldMatrix, 0.0f, -1.5f, 0.0f); 
					mFloor->Render();
					reflectionViewMatrix = camera->CalcualteReflectionMatrix(-1.5f);

					mReflectionShader->Render(mFloor->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, 
						Graphics::TextureResourceManager::GetInstance()->GetResource("Blue"), 
						&Graphics::Texture("Render Texture", mRenderTarget->GetTexture()->GetShaderResourceView()), reflectionViewMatrix);
				}
			break;

		case Refletion_State_PRE:
			reflectionViewMatrix = camera->CalcualteReflectionMatrix(-1.5f);

			mCube->Render();

			mTextureShader->Render(mCube->GetIndexCount(), 1, worldMatrix, reflectionViewMatrix, projectionMatrix, Graphics::TextureResourceManager::GetInstance()->GetResource("SeaFloor"));
			break;

		case Texture_State:
			if(mTextureShader)
			{
				mCube->Render();
				mTextureShader->Render(mCube->GetIndexCount(), mCube->GetModel()->GetInstanceCount(), worldMatrix, viewMatrix, projectionMatrix, Graphics::TextureResourceManager::GetInstance()->GetResource("SeaFloor"));
			}
			break;

		case Light_State:
			if(mLightShader)
			{
				// Update the rotation variable each frame.
				rotation += (float)D3DX_PI * 0.001f;
				if(rotation > 360.0f)
				{
					rotation -= 360.0f;
				}
				D3DXMatrixRotationY(&worldMatrix, rotation);

				mLightShader->Render(mCube->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, GetPlatform()->GetCamera()->As<Graphics::Camera>(), mLight, Graphics::TextureResourceManager::GetInstance()->GetResource("SeaFloor"));
			}
			break;
		default:
			break;
		}
	}
}

void CubeApp::EndGame()
{
	NGame::EndGame();
}

void CubeApp::PreRender()
{
	System::Win32Graphics* graphics = (System::Win32Graphics*)GetPlatform()->GetGraphics();
	Graphics::Camera* camera = GetPlatform()->GetCamera()->As<Graphics::Camera>();

	if(camera)
	{
		mCurrentState = Refletion_State_PRE;

		if(mRenderTarget)
		{
			graphics->RenderToTexture(mRenderTarget->GetTexture(), 0.0f);
		}

		mCurrentState = Refletion_State;
	}
}